home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / eforth51.zip / EFORTH.SRC < prev    next >
Text File  |  1990-07-26  |  19KB  |  867 lines

  1. \ eForth Initial Model (8086)
  2.  
  3. \ Based on bFORTH 1990 by Bill Muench, 1990
  4. \ Donated to eForth Working Group, Silicon Valley FIG Chapter
  5. \ to serve as a model of portable Forth for experimentation.
  6.  
  7. \ Conventions
  8.  \
  9.   \ <string>  characters in the input stream
  10.   \
  11.   \ a   aligned address
  12.   \ b   byte address
  13.   \ c   character
  14.   \ ca  code address
  15.   \ cy  carry
  16.   \ d   signed double integer
  17.   \ F   logical false
  18.   \ f   flag 0 or non-zero
  19.   \ la  link address
  20.   \ n   signed integer
  21.   \ na  name address
  22.   \ T   logical true
  23.   \ t   flag T or F
  24.   \ u   unsigned integer
  25.   \ ud  unsigned double integer
  26.   \ va  vocabulary address
  27.   \ w   unspecified weighted value
  28.  
  29. \ Header: token(ptr)  link(la)  name(na)
  30.  \
  31.   \ Count-byte and Lexicon bits  ioxn nnnn
  32.   \   i - immediate
  33.   \   o - compile-only
  34.   \   x - tag
  35.   \   n - string length  (31 characters MAX)
  36.   \ Compiler does not set bits in the NAME string
  37.   \ 0 < la na < .. < la na <    va < CONTEXT       @
  38.   \ 0 < FORTH < .. < vl va < vl va < CURRENT CELL+ @
  39.  
  40. .( Equates )
  41.  
  42. $xxxx EQU =RP   \ return stack base
  43. $xxxx EQU =SP   \ data stack base
  44. $xxxx EQU =UP   \ user base
  45. $xxxx EQU =TIB  \ default Terminal Input Buffer
  46.  
  47. $0080 EQU =IMED \ lexicom immediate bit
  48. $0040 EQU =COMP \ lexicom compile-only bit
  49. $7F1F EQU =MASK \ lexicon bit mask
  50.  
  51. $0001 EQU =BYTE \ size of a byte
  52. $0002 EQU =CELL \ size of a cell
  53.  
  54. $000A EQU =BASE \ default radix
  55. $0008 EQU =VOCS \ vocabulary stack depth
  56.  
  57. $E890 EQU =CALL \ 8086 CALL opcode (NOP CALL)
  58.  
  59. \ 8086 register useage
  60.  \
  61.   \ AX BX CX DX DI ES  free
  62.   \ SP              data stack pointer
  63.   \ BP              return stack pointer
  64.   \ SI              interpreter pointer
  65.   \ CS=DS=SS        segment pointers
  66.   \ IP              instruction pointer
  67.  
  68. \ The Forth inner interpreter
  69.  \
  70.   \ On the 8086 it is more efficient to compile
  71.   \ the inner interpreter as inline code.
  72.   \ On other processors it may be better
  73.   \ to jump to the routine.
  74.  
  75. MACRO NEXT ( -- )
  76.   LODS WORD \ 1 byte
  77.   JMP AX    \ 2 bytes
  78. END-MACRO
  79.  
  80. .( Special interpreters )
  81.  
  82. CODE doLIT ( -- w ) COMPILE-ONLY
  83.   LODS WORD \ r> dup 2+ >r @
  84.   PUSH AX
  85.   NEXT
  86. END-CODE
  87.  
  88. CODE doLIST ( a -- ) \ call dolist list..
  89.   XCHG BP, SP
  90.   PUSH SI     \ push on return stack
  91.   XCHG BP, SP
  92.   POP SI      \ new list address
  93.   NEXT
  94. END-CODE
  95.  
  96. CODE COLD ( -- )
  97.   JMP ORIG
  98.  
  99. CODE BYE
  100.   INT $20
  101.  
  102. CODE EXECUTE ( a -- )
  103.   POP BX
  104.   JMP BX
  105.  
  106. CODE EXIT ( -- )
  107.   XCHG BP, SP
  108.   POP SI      \ pop from return stack
  109.   XCHG BP, SP
  110.   NEXT
  111. END-CODE
  112.  
  113. .( Loop & Branch  16bit absolute address )
  114.  
  115. \ : next ( -- ) \ hiLevel model  16bit absolute branch
  116. \   r> r> dup if 1 - >r @ >r exit then drop cell+ >r ;
  117.  
  118. CODE next ( -- ) COMPILE-ONLY \ single index loop
  119.   SUB 0 [BP], # 1 WORD  \ decrement index
  120.   U>= IF                \ test index
  121.     MOV SI, 0 [SI]      \ continue looping, r> @ >r
  122.     NEXT
  123.   THEN
  124.   INC BP  INC BP        \ drop index (pop return stack)
  125. LABEL noBRAN
  126.   INC SI  INC SI        \ exit loop
  127.   NEXT
  128. END-CODE
  129.  
  130. CODE ?branch ( f -- ) COMPILE-ONLY
  131.   POP BX
  132.   OR BX, BX      \ test flag
  133.   JNZ noBRAN
  134.   MOV SI, 0 [SI] \ branch, r> @ >r
  135.   NEXT
  136. END-CODE
  137.  
  138. CODE branch ( -- ) COMPILE-ONLY
  139.   MOV SI, 0 [SI] \ r> @ >r
  140.   NEXT
  141. END-CODE
  142.  
  143. .( Memory fetch & store )
  144.  
  145. CODE ! ( w a -- )
  146.   POP BX
  147.   POP 0 [BX]
  148.   NEXT
  149. END-CODE
  150.  
  151. CODE @ ( a -- w )
  152.   POP BX
  153.   PUSH 0 [BX]
  154.   NEXT
  155. END-CODE
  156.  
  157. CODE C! ( w b -- )
  158.   POP BX
  159.   POP AX
  160.   MOV 0 [BX], AL
  161.   NEXT
  162. END-CODE
  163.  
  164. CODE C@ ( b -- c )
  165.   POP BX
  166.   XOR AX, AX
  167.   MOV AL, 0 [BX]
  168.   PUSH AX
  169.   NEXT
  170. END-CODE
  171.  
  172. .( Return Stack )
  173.  
  174. CODE RP@ ( -- a )
  175.   PUSH BP
  176.   NEXT
  177. END-CODE
  178.  
  179. CODE RP! ( a -- ) COMPILE-ONLY
  180.   POP BP
  181.   NEXT
  182. END-CODE
  183.  
  184. CODE R> ( -- w ) COMPILE-ONLY
  185.   PUSH 0 [BP]
  186.   INC BP  INC BP
  187.   NEXT
  188. END-CODE
  189.  
  190. CODE R@ ( -- w )
  191.   PUSH 0 [BP]
  192.   NEXT
  193. END-CODE
  194.  
  195. CODE >R ( w -- ) COMPILE-ONLY
  196.   DEC BP  DEC BP
  197.   POP 0 [BP]
  198.   NEXT
  199. END-CODE
  200.  
  201. .( Data Stack )
  202.  
  203. CODE SP@ ( -- a )
  204.   MOV BX, SP
  205.   PUSH BX
  206.   NEXT
  207. END-CODE
  208.  
  209. CODE SP! ( a -- )
  210.   POP SP
  211.   NEXT
  212. END-CODE
  213.  
  214. CODE DROP ( w -- )
  215.   INC SP  INC SP
  216.   NEXT
  217. END-CODE
  218.  
  219. CODE DUP ( w -- w w )
  220.   MOV BX, SP
  221.   PUSH 0 [BX]
  222.   NEXT
  223. END-CODE
  224.  
  225. CODE SWAP ( w1 w2 -- w2 w1 )
  226.   POP BX
  227.   POP AX
  228.   PUSH BX
  229.   PUSH AX
  230.   NEXT
  231. END-CODE
  232.  
  233. CODE OVER ( w1 w2 -- w1 w2 w1 )
  234.   MOV BX, SP
  235.   PUSH 2 [BX]
  236.   NEXT
  237. END-CODE
  238.  
  239. : ?DUP ( w -- w w, 0 ) DUP IF DUP THEN ;
  240.  
  241. : NIP ( w w -- w ) SWAP DROP ;
  242.  
  243. : ROT ( w1 w2 w3 -- w2 w3 w1 ) >R SWAP R> SWAP ;
  244.  
  245. : 2DROP ( w w  -- ) DROP DROP ;
  246.  
  247. : 2DUP ( w1 w2 -- w1 w2 w1 w2 ) OVER OVER ;
  248.  
  249. .( Logic )
  250.  
  251. CODE 0< ( n -- t )
  252.   POP AX
  253.   CWD
  254.   PUSH DX
  255.   NEXT
  256. END-CODE
  257.  
  258. CODE AND ( w w -- w )
  259.   POP BX
  260.   POP AX
  261.   AND BX, AX
  262.   PUSH BX
  263.   NEXT
  264. END-CODE
  265.  
  266. CODE OR ( w w -- w )
  267.   POP BX
  268.   POP AX
  269.   OR BX, AX
  270.   PUSH BX
  271.   NEXT
  272. END-CODE
  273.  
  274. CODE XOR ( w w -- w )
  275.   POP BX
  276.   POP AX
  277.   XOR BX, AX
  278.   PUSH BX
  279.   NEXT
  280. END-CODE
  281.  
  282. : INVERT ( w -- w ) -1 XOR ;
  283.  
  284. .( Arithmetic )
  285.  
  286. CODE UM+ ( u u -- u cy ) \ or ( u u -- ud )
  287.   XOR CX, CX
  288.   POP BX
  289.   POP AX
  290.   ADD AX, BX
  291.   RCL CX, # 1 \ pick up carry
  292.   PUSH AX
  293.   PUSH CX
  294.   NEXT
  295. END-CODE
  296.  
  297. : + ( u u -- u ) UM+ DROP ;
  298.  
  299. :  NEGATE ( n -- -n ) INVERT 1 + ;
  300. : DNEGATE ( d -- -d ) INVERT >R INVERT 1 UM+ R> + ;
  301.  
  302. : - ( w w -- w ) NEGATE + ;
  303.  
  304. : ABS ( n -- +n ) DUP 0< IF NEGATE THEN ;
  305.  
  306. .( User variables )
  307.  
  308. : doUSER ( -- a ) R> @ UP @ + ; COMPILE-ONLY
  309.  
  310. : doVAR ( -- a ) R> ; COMPILE-ONLY
  311.  
  312. 8 \ start offset
  313.  
  314. DUP USER SP0      1 CELL+ \ initial data stack pointer
  315. DUP USER RP0      1 CELL+ \ initial return stack pointer
  316.  
  317. DUP USER '?KEY    1 CELL+ \ character input ready vector
  318. DUP USER 'EMIT    1 CELL+ \ character output vector
  319.  
  320. DUP USER 'EXPECT  1 CELL+ \ line input vector
  321. DUP USER 'TAP     1 CELL+ \ input case vector
  322. DUP USER 'ECHO    1 CELL+ \ input echo vector
  323. DUP USER 'PROMPT  1 CELL+ \ operator prompt vector
  324.  
  325. DUP USER BASE     1 CELL+ \ number base
  326.  
  327. DUP USER temp     1 CELL+ \ scratch
  328. DUP USER SPAN     1 CELL+ \ #chars input by EXPECT
  329. DUP USER >IN      1 CELL+ \ input buffer offset
  330. DUP USER #TIB     1 CELL+ \ #chars in the input buffer
  331.       1 CELLS ALLOT \   address  of input buffer
  332.  
  333. DUP USER UP       1 CELL+ \ user base pointer
  334. DUP USER CSP      1 CELL+ \ save stack pointers
  335. DUP USER 'EVAL    1 CELL+ \ interpret/compile vector
  336. DUP USER 'NUMBER  1 CELL+ \ numeric input vector
  337. DUP USER HLD      1 CELL+ \ formated numeric string
  338. DUP USER HANDLER  1 CELL+ \ error frame pointer
  339.  
  340. DUP USER CONTEXT  1 CELL+ \ first search vocabulary
  341.   =VOCS CELL+ \ vocabulary stack
  342.  
  343. DUP USER CURRENT  1 CELL+ \ definitions vocabulary
  344.       1 CELL+ \ newest vocabulary
  345.  
  346. DUP USER CP       1 CELL+ \ dictionary code pointer
  347.       1 CELL+ \ dictionary name pointer
  348.       1 CELL+ \ last name compiled
  349.  
  350. ?USER
  351.  
  352. .( Comparison )
  353.  
  354. : 0= ( w -- t ) IF 0 EXIT THEN -1 ;
  355.  
  356. : = ( w w -- t ) XOR 0= ;
  357.  
  358. : U< ( u u -- t ) 2DUP XOR 0< IF  NIP 0< EXIT THEN - 0< ;
  359. :  < ( n n -- t ) 2DUP XOR 0< IF DROP 0< EXIT THEN - 0< ;
  360.  
  361. : MAX ( n n -- n ) 2DUP      < IF SWAP THEN DROP ;
  362. : MIN ( n n -- n ) 2DUP SWAP < IF SWAP THEN DROP ;
  363.  
  364. : WITHIN ( u ul uh -- t ) OVER - >R - R> U< ;
  365.  
  366. .( Divide )
  367.  
  368. : UM/MOD ( udl udh un -- ur uq )
  369.   2DUP U<
  370.   IF NEGATE  15
  371.     FOR >R DUP  UM+  >R >R DUP  UM+  R> + DUP
  372.         R> R@ SWAP >R  UM+  R> OR
  373.       IF >R DROP 1 + R> ELSE DROP THEN R>
  374.     NEXT DROP SWAP EXIT
  375.   THEN DROP 2DROP  -1 DUP ;
  376.  
  377. : M/MOD ( d n -- r q ) \ floored
  378.   DUP 0<  DUP >R
  379.   IF NEGATE >R DNEGATE R>
  380.   THEN >R DUP 0< IF R@ + THEN R> UM/MOD R>
  381.   IF SWAP NEGATE SWAP THEN ;
  382.  
  383. : /MOD ( n n -- r q ) OVER 0< SWAP M/MOD ;
  384. : MOD ( n n -- r ) /MOD DROP ;
  385. : / ( n n -- q ) /MOD NIP ;
  386.  
  387. .( Multiply )
  388.  
  389. : UM* ( u1 u2 -- ud )
  390.   0 SWAP ( u1 0 u2 ) 15
  391.   FOR DUP  UM+  >R >R DUP  UM+  R> + R>
  392.     IF >R OVER  UM+  R> + THEN
  393.   NEXT ROT DROP ;
  394.  
  395. : * ( n n -- n ) UM* DROP ;
  396.  
  397. : M* ( n n -- d )
  398.   2DUP XOR 0< >R  ABS SWAP ABS UM*  R> IF DNEGATE THEN ;
  399.  
  400. : */MOD ( n n n -- r q ) >R M* R> M/MOD ;
  401. : */ ( n n n -- q ) */MOD NIP ;
  402.  
  403. .( Bits & Bytes )
  404.  
  405. : BYTE+ ( b -- b ) [ =BYTE ] LITERAL + ;
  406. : CELL+ ( a -- a ) [ =CELL ] LITERAL + ;
  407.  
  408. : CELLS ( n -- n ) [ =CELL ] LITERAL * ;
  409.  
  410. : BL ( -- 32 ) 32 ;
  411.  
  412. : >CHAR ( c -- c )
  413.   127 AND DUP 127 BL WITHIN IF [ CHAR _ ] LITERAL NIP THEN ;
  414.  
  415. : DEPTH ( -- n ) SP@ SP0 @ SWAP - 2 / ;
  416.  
  417. : PICK ( +n -- w ) 1 + CELLS SP@ + @ ;
  418.  
  419. : ALIGNED ( b -- a ) ; IMMEDIATE
  420.  
  421. .( Memory access )
  422.  
  423. : +! ( n a -- ) SWAP OVER @ + SWAP ! ;
  424.  
  425. : 2! ( d a -- ) SWAP OVER ! CELL+ ! ;
  426. : 2@ ( a -- d ) DUP CELL+ @ SWAP @ ;
  427.  
  428. : COUNT ( b -- b +n ) DUP 1 + SWAP C@ ;
  429.  
  430. : HERE ( -- a ) CP @ ;
  431. : PAD ( -- a ) HERE 80 + ;
  432. : TIB ( -- a ) #TIB CELL+ @ ;
  433.  
  434. : NP ( -- a ) CP CELL+ ;
  435. : LAST ( -- a ) NP CELL+ ;
  436.  
  437. : @EXECUTE ( a -- ) @ ?DUP IF EXECUTE THEN ;
  438.  
  439. : CMOVE ( b b u -- )
  440.   FOR AFT >R COUNT R@ C! R> 1 + THEN NEXT 2DROP ;
  441.  
  442. : -TRAILING ( b u -- b u )
  443.   FOR AFT DUP R@ + C@  BL XOR
  444.     IF R> 1 + EXIT THEN THEN
  445.   NEXT 0 ;
  446.  
  447. : FILL ( b u c -- )
  448.   SWAP FOR SWAP AFT 2DUP C! 1 + THEN NEXT 2DROP ;
  449.  
  450. : ERASE ( b u -- ) 0 FILL ;
  451.  
  452. : PACK$ ( b u a -- a ) \ null terminated
  453.   DUP >R  2DUP C! 1 + 2DUP +  0  SWAP ! SWAP CMOVE  R> ;
  454.  
  455. .( Numeric Output ) \ single precision
  456.  
  457. : DIGIT ( u -- c ) 9 OVER < 7 AND + [ CHAR 0 ] LITERAL + ;
  458. : EXTRACT ( n base -- n c ) 0 SWAP UM/MOD SWAP DIGIT ;
  459.  
  460. : <# ( -- ) PAD HLD ! ;
  461.  
  462. : HOLD ( c -- ) HLD @ 1 - DUP HLD ! C! ;
  463.  
  464. : # ( u -- u ) BASE @ EXTRACT HOLD ;
  465.  
  466. : #S ( u -- 0 ) BEGIN # DUP WHILE REPEAT ;
  467.  
  468. : SIGN ( n -- ) 0< IF [ CHAR - ] LITERAL HOLD THEN ;
  469.  
  470. : #> ( w -- b u ) DROP HLD @ PAD OVER - ;
  471.  
  472. : str ( w -- b u ) DUP >R ABS <# #S R> SIGN #> ;
  473.  
  474. : HEX ( -- ) 16 BASE ! ;
  475. : DECIMAL ( -- ) 10 BASE ! ;
  476.  
  477. .( Numeric Input ) \ single precision
  478.  
  479. : DIGIT? ( c base -- u t )
  480.   >R [ CHAR 0 ] LITERAL - 9 OVER <
  481.   IF 7 - DUP 10 < OR THEN DUP R> U< ;
  482.  
  483. : NUMBER? ( a -- n T, a F )
  484.   BASE @ >R  0 OVER COUNT ( a 0 b n)
  485.   OVER C@ [ CHAR $ ] LITERAL =
  486.   IF HEX SWAP BYTE+ SWAP 1 - THEN ( a 0 b' n')
  487.   OVER C@ [ CHAR - ] LITERAL = >R ( a 0 b n)
  488.   SWAP R@ - SWAP R@ + ( a 0 b" n") ?DUP
  489.   IF 1 - ( a 0 b n)
  490.     FOR DUP >R C@ BASE @ DIGIT?
  491.       WHILE SWAP BASE @ * +  R> BYTE+
  492.     NEXT R@ ( ?sign) NIP ( b) IF NEGATE THEN SWAP
  493.       ELSE R> R> ( b index) 2DROP ( digit number) 2DROP 0
  494.       THEN DUP
  495.   THEN R> ( n ?sign) 2DROP R> BASE ! ;
  496.  
  497. .( Basic I/O )
  498.  
  499. : KEY? ( -- f ) '?KEY @EXECUTE ;
  500. : KEY ( -- c ) BEGIN '?KEY UNTIL ;
  501. : EMIT ( c -- ) 'EMIT @EXECUTE ;
  502.  
  503. : NUF? ( -- f ) KEY? DUP IF KEY 2DROP KEY 13 = THEN ;
  504.  
  505. :  PACE ( -- ) 11 EMIT ;
  506. : SPACE ( -- ) BL EMIT ;
  507.  
  508. : CHARS ( +n c -- ) SWAP 0 MAX FOR AFT DUP EMIT THEN NEXT DROP ;
  509.  
  510. : SPACES ( +n -- ) BL CHARS ;
  511.  
  512. : do$ ( -- a )
  513.   R> R@ R> COUNT + ALIGNED >R SWAP >R ; COMPILE-ONLY
  514.  
  515. : $"| ( -- a ) do$ ; COMPILE-ONLY
  516.  
  517. : TYPE ( b u -- ) FOR AFT COUNT EMIT THEN NEXT DROP ;
  518.  
  519. : .$ ( a -- ) COUNT TYPE ;
  520.  
  521. : ."| ( -- ) do$ .$ ; COMPILE-ONLY
  522.  
  523. : CR ( -- ) 13 EMIT 10 EMIT ;
  524.  
  525. :  .R ( n +n -- ) >R str      R> OVER - SPACES TYPE ;
  526. : U.R ( u +n -- ) >R <# #S #> R> OVER - SPACES TYPE ;
  527.  
  528. : U. ( u -- ) <# #S #> SPACE TYPE ;
  529. :  . ( w -- ) BASE @ 10 XOR IF U. EXIT THEN str SPACE TYPE ;
  530.  
  531. : ? ( a -- ) @ . ;
  532.  
  533. .( Parsing )
  534.  
  535. : parse ( b u c -- b u delta \ <string> )
  536.   temp !  OVER >R  DUP \ b u u
  537.   IF 1 -  temp @ BL =
  538.     IF \ b u' \ 'skip'
  539.       FOR COUNT temp @  SWAP - 0< INVERT  WHILE
  540.       NEXT ( b) R> DROP 0 DUP EXIT \ all delim
  541.         THEN  1 -  R>
  542.     THEN OVER SWAP \ b' b' u' \ 'scan'
  543.     FOR COUNT temp @ SWAP -  temp @ BL =
  544.       IF 0< THEN WHILE
  545.     NEXT DUP >R  ELSE R> DROP DUP >R 1 -
  546.                  THEN OVER -  R>  R> - EXIT
  547.   THEN ( b u) OVER R> - ;
  548.  
  549. : PARSE ( c -- b u \ <string> )
  550.   >R  TIB >IN @ +  #TIB @ >IN @ -  R> parse >IN +! ;
  551.  
  552. : .( ( -- ) [ CHAR ) ] LITERAL PARSE TYPE ; IMMEDIATE
  553. : ( ( -- ) [ CHAR ) ] LITERAL PARSE 2DROP ; IMMEDIATE
  554. : \ ( -- ) #TIB @ >IN ! ; IMMEDIATE
  555.  
  556. : CHAR ( -- c ) BL PARSE DROP C@ ;
  557. : CTRL ( -- c ) CHAR $001F AND ;
  558.  
  559. : TOKEN ( -- a \ <string> )
  560.   BL PARSE 31 MIN NP @ OVER - 2 - PACK$ ;
  561.  
  562. : WORD ( c -- a \ <string> ) PARSE HERE PACK$ ;
  563.  
  564. .( Dictionary Search )
  565.  
  566. : NAME> ( na -- ca ) 2 CELLS - @ ;
  567.  
  568. : SAME? ( a a u -- a a f \ -0+ )
  569.   FOR AFT OVER R@ CELLS + @
  570.           OVER R@ CELLS + @ -  ?DUP
  571.     IF R> DROP EXIT THEN THEN
  572.   NEXT 0 ;
  573.  
  574. : find ( a va -- ca na, a F )
  575.   SWAP              \ va a
  576.   DUP C@ 2 / temp ! \ va a  \ get cell count
  577.   DUP @ >R          \ va a  \ count byte & 1st char
  578.   CELL+ SWAP        \ a' va
  579.   BEGIN @ DUP       \ a' na na
  580.     IF DUP @ [ =MASK ] LITERAL AND  R@ XOR \ ignore lexicon bits
  581.       IF CELL+ -1 ELSE CELL+ temp @ SAME? THEN
  582.     ELSE R> DROP EXIT
  583.     THEN
  584.   WHILE 2 CELLS -   \ a' la
  585.   REPEAT R> DROP NIP 1 CELLS -  DUP NAME> SWAP ;
  586.  
  587. : NAME? ( a -- ca na, a F )
  588.   CONTEXT  DUP 2@ XOR IF 1 CELLS - THEN >R \ context<>also
  589.   BEGIN R>  CELL+  DUP >R  @  ?DUP
  590.   WHILE find  ?DUP
  591.   UNTIL R> DROP EXIT THEN R> DROP  0 ;
  592.  
  593. .( Terminal )
  594.  
  595. : ^H ( b b b -- b b b ) \ backspace
  596.   >R OVER R@ < DUP
  597.   IF [ CTRL H ] LITERAL 'ECHO @EXECUTE THEN R> + ;
  598.  
  599. : TAP ( bot eot cur key -- bot eot cur )
  600.   DUP 'ECHO @EXECUTE OVER C! 1 + ;
  601.  
  602. : kTAP ( bot eot cur key -- bot eot cur )
  603.   DUP 13 XOR
  604.   IF [ CTRL H ] LITERAL XOR IF BL TAP ELSE ^H THEN EXIT
  605.   THEN DROP NIP DUP ;
  606.  
  607. : accept ( b u -- b u )
  608.   OVER + OVER
  609.   BEGIN 2DUP XOR
  610.   WHILE  KEY  DUP BL -  95 U<
  611.     IF TAP ELSE 'TAP @EXECUTE THEN
  612.   REPEAT DROP  OVER - ;
  613.  
  614. : EXPECT ( b u -- ) 'EXPECT @EXECUTE SPAN ! DROP ;
  615.  
  616. : QUERY ( -- )
  617.   TIB 80 'EXPECT @EXECUTE #TIB !  0 NIP >IN ! ;
  618.  
  619. .( Error handling )
  620.  
  621. : CATCH ( ca -- err#/0 )
  622.   SP@ >R  HANDLER @ >R  RP@ HANDLER !
  623.   EXECUTE
  624.   R> HANDLER !  R> DROP  0 ;
  625.  
  626. : THROW ( err# -- err# )
  627.   HANDLER @ RP!  R> HANDLER !  R> SWAP >R SP! DROP R> ;
  628.                         
  629. CREATE NULL$ 0 ,
  630.  
  631. : ABORT ( -- ) NULL$ THROW ;
  632.  
  633. : abort" ( f -- ) IF do$ THROW THEN do$ DROP ; COMPILE-ONLY
  634.  
  635. .( Interpret )
  636.  
  637. : $INTERPRET ( a -- )
  638.   NAME?  ?DUP
  639.   IF @ [ =COMP ] LITERAL AND
  640.     ABORT" compile ONLY" EXECUTE EXIT
  641.   THEN
  642.   'NUMBER @EXECUTE
  643.   IF EXIT THEN THROW ;
  644.  
  645. : [ ( -- ) [ ' $INTERPRET ] LITERAL 'EVAL ! ; IMMEDIATE
  646.  
  647. : .OK ( -- ) [ ' $INTERPRET ] LITERAL 'EVAL @ = IF ."  ok" THEN CR ;
  648.  
  649. : ?STACK ( -- ) DEPTH 0< IF $" underflow" THROW THEN ;
  650.  
  651. : EVAL ( -- )
  652.   BEGIN TOKEN DUP C@
  653.   WHILE 'EVAL @EXECUTE ?STACK
  654.   REPEAT DROP 'PROMPT @EXECUTE ;
  655.  
  656. .( Device I/O )
  657.  
  658. CODE IO? ( -- f ) \ FFFF is an impossible character
  659.   XOR BX, BX
  660.   MOV DL, # $0FF  \ input
  661.   MOV AH, # 6     \ MS-DOS Direct Console I/O
  662.   INT $021
  663.   0<> IF          \ ?key ready
  664.     OR AL, AL
  665.     0= IF         \ ?extended ascii code
  666.       INT $021
  667.       MOV BH, AL  \ extended code in msb
  668.     ELSE MOV BL, AL
  669.     THEN
  670.     PUSH BX
  671.     MOVE BX, # -1
  672.   THEN
  673.   PUSH BX
  674.   NEXT
  675. END-CODE
  676.  
  677. CODE TX! ( c -- )
  678.   POP DX
  679.   CMP DL, # $0FF
  680.   0= IF          \ do NOT allow input
  681.     MOV DL, # 32  \ change to blank
  682.   THEN
  683.   MOV AH, # 6    \ MS-DOS Direct Console I/O
  684.   INT $021
  685.   NEXT
  686. END-CODE
  687.  
  688. : !IO ( -- ) ; IMMEDIATE \ initialize I/O device
  689.  
  690. .( Shell )
  691.  
  692. : PRESET ( -- ) SP0 @ SP!  [ =TIB ] LITERAL #TIB CELL+ ! ;
  693.  
  694. : XIO ( a a a -- ) \ reset 'EXPECT 'TAP 'ECHO 'PROMPT
  695.   [ ' accept ] LITERAL 'EXPECT !
  696.   'TAP !  'ECHO !  'PROMPT ! ;
  697.  
  698. : FILE ( -- )
  699.   [ ' PACE ] LITERAL [ ' DROP ] LITERAL [ ' kTAP ] LITERAL XIO ;
  700.  
  701. : HAND ( -- )
  702.   [ ' .OK  ] LITERAL 'EMIT @ [ ' kTAP ] LITERAL XIO ;
  703.  
  704. CREATE I/O  ' RX? , ' TX! , \ defaults
  705.  
  706. : CONSOLE ( -- ) I/O 2@ 'KEY? 2! HAND ;
  707.  
  708. : que ( -- ) QUERY EVAL ;
  709.  
  710. : QUIT ( -- ) \ clear return stack ONLY
  711.   RP0 @ RP!
  712.   BEGIN [COMPILE] [
  713.     BEGIN [ ' que ] LITERAL CATCH ?DUP
  714.     UNTIL ( a)
  715.     CONSOLE  NULL$ OVER XOR
  716.     IF CR TIB #TIB @ TYPE
  717.        CR >IN @ [ CHAR ^ ] LITERAL CHARS
  718.        CR .$ ."  ? "
  719.     THEN PRESET
  720.   AGAIN ;
  721.  
  722. .( Compiler Primitives )
  723.  
  724. : ' ( -- ca ) TOKEN NAME? IF EXIT THEN THROW ;
  725.  
  726. : ALLOT ( n -- ) CP +! ;
  727.  
  728. : , ( w -- ) HERE ALIGNED DUP CELL+ CP ! ! ;
  729.  
  730. : [COMPILE] ( -- \ <string> ) ' , ; IMMEDIATE
  731.  
  732. : COMPILE ( -- ) R> DUP @ , CELL+ >R ; COMPILE-ONLY
  733.  
  734. : LITERAL ( w -- ) COMPILE doLIT , ; IMMEDIATE
  735.  
  736. : $," ( -- ) [ CHAR " ] LITERAL PARSE HERE PACK$ C@ 1 + ALLOT ;
  737.  
  738. : RECURSE ( -- ) LAST @ CURRENT @ ! ; IMMEDIATE
  739.  
  740. .( Structures )
  741.  
  742. : FOR ( -- a ) COMPILE >R HERE ; IMMEDIATE
  743. : BEGIN ( -- a ) HERE ; IMMEDIATE
  744. : NEXT ( a -- ) COMPILE next , ; IMMEDIATE
  745. : UNTIL ( a -- ) COMPILE ?branch , ; IMMEDIATE
  746. : AGAIN ( a -- ) COMPILE  branch , ; IMMEDIATE
  747. : IF ( -- A )   COMPILE ?branch HERE 0 , ; IMMEDIATE
  748. : AHEAD ( -- A ) COMPILE branch HERE 0 , ; IMMEDIATE
  749. : REPEAT ( A a -- ) [COMPILE] AGAIN HERE SWAP ! ; IMMEDIATE
  750. : THEN ( A -- ) HERE SWAP ! ; IMMEDIATE
  751. : AFT ( a -- a A ) DROP [COMPILE] AHEAD [COMPILE] BEGIN SWAP ; IMMEDIATE
  752. : ELSE ( A -- A )  [COMPILE] AHEAD SWAP [COMPILE] THEN ; IMMEDIATE
  753. : WHILE ( a -- A a )    [COMPILE] IF SWAP ; IMMEDIATE
  754.  
  755. : ABORT" ( -- \ <string> ) COMPILE abort" $," ; IMMEDIATE
  756.  
  757. : $" ( -- \ <string> ) COMPILE $"| $," ; IMMEDIATE
  758. : ." ( -- \ <string> ) COMPILE ."| $," ; IMMEDIATE
  759.  
  760. .( Name Compiler )
  761.  
  762. : ?UNIQUE ( a -- a )
  763.   DUP NAME? IF ."  reDef " OVER .$ THEN DROP ;
  764.  
  765. : $,n ( na -- )
  766.   DUP C@
  767.   IF ?UNIQUE
  768.     ( na) DUP LAST ! \ for OVERT
  769.     ( na) HERE ALIGNED SWAP
  770.     ( cp na) 1 CELLS -
  771.     ( cp la) CURRENT @ @
  772.     ( cp la na') OVER !
  773.     ( cp la) 1 CELLS - DUP NP ! ( ptr) ! EXIT
  774.   THEN $" name" THROW ;
  775.  
  776. .( FORTH Compiler )
  777.  
  778. : $COMPILE ( a -- )
  779.   NAME? ?DUP
  780.   IF C@ [ =IMED ] LITERAL AND
  781.     IF EXECUTE ELSE , THEN EXIT
  782.   THEN
  783.   'NUMBER @EXECUTE
  784.   IF [COMPILE] LITERAL EXIT
  785.   THEN THROW ;
  786.  
  787. : OVERT ( -- ) LAST @ CURRENT @  ! ;
  788.  
  789. : ; ( -- )
  790.   COMPILE EXIT [COMPILE] [ OVERT ; COMPILE-ONLY IMMEDIATE
  791.  
  792. : ] ( -- ) [ ' $COMPILE ] LITERAL 'EVAL ! ;
  793.  
  794. : CALL, ( ca -- ) \  DTC 8086 relative call
  795.   [ =CALL ] LITERAL , HERE CELL+ - , ;
  796.  
  797. : : ( -- \ <string> ) TOKEN $,n [ ' doLIST ] LITERAL CALL, ] ;
  798.  
  799. : IMMEDIATE ( -- ) [ =IMED ] LITERAL LAST @ C@ OR LAST @ C! ;
  800.  
  801. .( Defining Words )
  802.  
  803. : USER ( u -- \ <string> ) TOKEN $,n OVERT COMPILE doUSER , ;
  804.  
  805. : CREATE ( -- \ <string> ) TOKEN $,n OVERT COMPILE doVAR ;
  806.  
  807. : VARIABLE ( -- \ <string> ) CREATE 0 , ;
  808.  
  809. .( Tools )
  810.  
  811. : _TYPE ( b u -- ) FOR AFT COUNT >CHAR EMIT THEN NEXT DROP ;
  812.  
  813. : dm+ ( b u -- b )
  814.   OVER 4 U.R SPACE FOR AFT COUNT 3 U.R THEN NEXT ;
  815.  
  816. : DUMP ( b u -- )
  817.   BASE @ >R HEX  16 /
  818.   FOR CR 16 2DUP dm+ -ROT 2 SPACES _TYPE NUF? 0= WHILE
  819.   NEXT ELSE R> DROP THEN DROP  R> BASE ! ;
  820.  
  821. : .S ( -- ) CR DEPTH FOR AFT R@ PICK . THEN NEXT ."  <tos" ;
  822.  
  823. : !CSP ( -- ) SP@ CSP ! ;
  824. : ?CSP ( -- ) SP@ CSP @ XOR ABORT" stack depth" ;
  825.  
  826. : >NAME ( ca -- na, F )
  827.   CURRENT
  828.   BEGIN CELL+ @ ?DUP WHILE 2DUP
  829.     BEGIN @ DUP WHILE 2DUP NAME> XOR
  830.     WHILE 1 CELLS -
  831.     REPEAT      THEN NIP ?DUP
  832.   UNTIL NIP NIP EXIT THEN 0 NIP ;
  833.  
  834. : .ID ( na -- )
  835.   ?DUP IF COUNT $001F AND TYPE EXIT THEN ." {noName}" ;
  836.  
  837. : WORDS ( -- )
  838.   CR  CONTEXT @
  839.   BEGIN @ ?DUP
  840.   WHILE DUP SPACE .ID 1 CELLS -  NUF?
  841.   UNTIL DROP THEN ;
  842.  
  843. .( Hardware reset )
  844.  
  845. \ version
  846.  
  847. $100 CONSTANT VER ( -- u )
  848.   \ hi byte = major revision in decimal
  849.   \ lo byte = minor revision in decimal
  850.  
  851. : hi ( -- )
  852.   !IO \ initialize IO device & sign on
  853.   CR ." eForth v1.0"
  854.   ; COMPILE-ONLY
  855.  
  856. CREATE 'BOOT  ' hi , \ application vector
  857.  
  858. : COLD ( -- )
  859.   \ init CPU
  860.   \ init stacks
  861.   \ init user area
  862.   \ init IP
  863.   PRESET  'BOOT @EXECUTE
  864.   QUIT ;
  865.  
  866.  
  867.